function u=diffusion_scheme_3D_implicit(u,Dxx,Dxy,Dxz,Dyy,Dyz,Dzz,dt)
% This 3D Diffusion scheme is based on introduced by Weickert  
% "Anisotropic Diffusion  in Image Processing", Thesis 1996. 
%
% !! Scheme is unstable, and not ready to use yet.
% 
% Function is written by D.Kroon University of Twente (September 2009)


%  Positive and negative image indices
[N1,N2,N3] = size(u);
id = [2:N1,N1]; iu = [1,1:N1-1];
ir = [2:N2,N2]; il = [1,1:N2-1];
ib = [2:N3,N3]; iv = [1,1:N3-1];

% Diagonal neighbor intensity updates (amount of greyvalue flow from
% neighbor) 
Dulc = max(0,-Dxy(iu,il,:)) + max(0,-Dxy); 
Ddrc = max(0,-Dxy(id,ir,:)) + max(0,-Dxy);
Ddlc = max(0, Dxy(id,il,:)) + max(0, Dxy);
Durc = max(0, Dxy(iu,ir,:)) + max(0, Dxy);

Ducv = max(0,-Dxz(iu,:,iv)) + max(0,-Dxz); 
Ddcb = max(0,-Dxz(id,:,ib)) + max(0,-Dxz);
Ddcv = max(0, Dxz(id,:,iv)) + max(0, Dxz);
Ducb = max(0, Dxz(iu,:,ib)) + max(0, Dxz);

Dclv = max(0,-Dyz(:,il,iv)) + max(0,-Dyz); 
Dcrb = max(0,-Dyz(:,ir,ib)) + max(0,-Dyz);
Dcrv = max(0, Dyz(:,ir,iv)) + max(0, Dyz);
Dclb = max(0, Dyz(:,il,ib)) + max(0, Dyz);

% Normal neighbor intensity updates 
Ducc = (Dxx(iu,:,:) + Dxx) - (abs(Dxy(iu,:,:)) + abs(Dxy)) - (abs(Dxz(iu,:,:)) + abs(Dxz));
Ddcc = (Dxx(id,:,:) + Dxx) - (abs(Dxy(id,:,:)) + abs(Dxy)) - (abs(Dxz(id,:,:)) + abs(Dxz));
Dclc = (Dyy(:,il,:) + Dyy) - (abs(Dxy(:,il,:)) + abs(Dxy)) - (abs(Dyz(:,il,:)) + abs(Dyz));
Dcrc = (Dyy(:,ir,:) + Dyy) - (abs(Dxy(:,ir,:)) + abs(Dxy)) - (abs(Dyz(:,ir,:)) + abs(Dyz));
Dccv = (Dzz(:,:,iv) + Dzz) - (abs(Dxz(:,:,iv)) + abs(Dxz)) - (abs(Dyz(:,:,iv)) + abs(Dyz));
Dccb = (Dzz(:,:,ib) + Dzz) - (abs(Dxz(:,:,ib)) + abs(Dxz)) - (abs(Dyz(:,:,ib)) + abs(Dyz));

% Normalization term to preserve region average grey value
Dccc = -(Dzz(:,:,iv) + 2*Dzz + Dzz(:,:,ib)) + ... 
       -(Dyy(:,il,:) + 2*Dyy + Dyy(:,ir,:)) + ... 
       -(Dxx(iu,:,:) + 2*Dxx + Dxx(id,:,:)) + ...  
        -max(0,-Dxy(iu,il,:)) + ...
        -max(0,-Dxy(id,ir,:)) + ...
        -max(0, Dxy(id,il,:)) + ...
        -max(0, Dxy(iu,ir,:)) + ...
        -max(0,-Dxz(iu,:,iv)) + ...
        -max(0,-Dxz(id,:,ib)) + ...
        -max(0, Dxz(id,:,iv)) + ...
        -max(0, Dxz(iu,:,ib)) + ...
        -max(0,-Dyz(:,il,iv)) + ...
        -max(0,-Dyz(:,ir,ib)) + ...
        -max(0, Dyz(:,ir,iv)) + ...
        -max(0, Dyz(:,il,ib)) + ...
       (abs(Dxy(:,il,:)) + abs(Dxy(:,ir,:)) + ...
        abs(Dxy(id,:,:)) + abs(Dxy(iu,:,:)) + ...
        abs(Dxz(id,:,:)) + abs(Dxz(iu,:,:)) + ...
        abs(Dxz(:,:,iv)) + abs(Dxz(:,:,ib)) + ...
        abs(Dyz(:,il,:)) + abs(Dyz(:,ir,:)) + ...
        abs(Dyz(:,:,iv)) + abs(Dyz(:,:,ib)) + ...
        2*abs(Dxy) + 2*abs(Dxz) + 2*abs(Dyz));

% Calculate Diffusion update 
du=0.5*dt*( Ducc.*u(iu,: ,: )  +  Ddcc.*u(id,: ,: )  + ...
            Dclc.*u(: ,il,: )  +  Dcrc.*u(: ,ir,: )  + ...
            Dccv.*u(: ,: ,iv)  +  Dccb.*u(: ,: ,ib)  + ...
            Dulc.*u(iu,il,: )  +  Ddlc.*u(id,il,: )  + ...
            Durc.*u(iu,ir,: )  +  Ddrc.*u(id,ir,: )  + ...
            Ducv.*u(iu,: ,iv)  +  Ddcb.*u(id,: ,ib)  + ...
            Ducb.*u(iu,: ,ib)  +  Ddcv.*u(id,: ,iv)  + ...
            Dclv.*u(: ,il,iv)  +  Dcrb.*u(: ,ir,ib)  + ...
            Dclb.*u(: ,il,ib)  +  Dcrv.*u(: ,ir,iv));

% Perform the edge preserving diffusion filtering on the image
u = (u + du )./ (1-dt*0.5*Dccc);  %